﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace Pixysoft.Security
{
    /// <summary>
    /// http://www.cnblogs.com/yuanbao/archive/2007/09/25/905322.html
    /// </summary>
    public class UnCodebase
    {
        public Bitmap bmpobj;

        public UnCodebase()
        {
            bmpobj = null;
        }
        public UnCodebase(Bitmap pic)
        {
            bmpobj = new Bitmap(pic);    //转换为Format32bppRgb
        }


        /// <summary>
        /// 平均分割图片
        /// </summary>
        /// <param name="RowNum">水平上分割数</param>
        /// <param name="ColNum">垂直上分割数</param>
        /// <returns>分割好的图片数组</returns>
        private Bitmap[] GetSplitPics(int RowNum, int ColNum)
        {
            if (RowNum == 0 || ColNum == 0)
                return null;
            int singW = bmpobj.Width / RowNum;
            int singH = bmpobj.Height / ColNum;
            Bitmap[] PicArray = new Bitmap[RowNum * ColNum];

            Rectangle cloneRect;
            for (int i = 0; i < ColNum; i++)      //找有效区
            {
                for (int j = 0; j < RowNum; j++)
                {
                    cloneRect = new Rectangle(j * singW, i * singH, singW, singH);
                    PicArray[i * RowNum + j] = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);//复制小块图
                }
            }
            return PicArray;
        }
        /// <summary>
        /// 灰度转换,逐行方式
        /// </summary>
        private void GrayByLine()
        {
            Rectangle rec = new Rectangle(0, 0, bmpobj.Width, bmpobj.Height);
            BitmapData bmpData = bmpobj.LockBits(rec, ImageLockMode.ReadWrite, bmpobj.PixelFormat);// PixelFormat.Format32bppPArgb);
            //    bmpData.PixelFormat = PixelFormat.Format24bppRgb;
            IntPtr scan0 = bmpData.Scan0;
            int len = bmpobj.Width * bmpobj.Height;
            int[] pixels = new int[len];
            Marshal.Copy(scan0, pixels, 0, len);

            //对图片进行处理
            int GrayValue = 0;
            for (int i = 0; i < len; i++)
            {
                GrayValue = GetGrayNumColor(Color.FromArgb(pixels[i]));
                pixels[i] = (byte)(Color.FromArgb(GrayValue, GrayValue, GrayValue)).ToArgb();      //Color转byte
            }

            bmpobj.UnlockBits(bmpData);
        }




        /// <summary>
        /// 灰度转换,逐点方式
        /// </summary>
        public void GrayByPixels()
        {
            for (int i = 0; i < bmpobj.Height; i++)
            {
                for (int j = 0; j < bmpobj.Width; j++)
                {
                    int tmpValue = GetGrayNumColor(bmpobj.GetPixel(j, i));
                    bmpobj.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue));
                }
            }
        }
        /// <summary>
        /// 二值
        /// </summary>
        public void SecondGrayByPixels(int grayGate)
        {
            for (int i = 0; i < bmpobj.Height; i++)
            {
                for (int j = 0; j < bmpobj.Width; j++)
                {
                    int tmpValue = GetGrayNumColor(bmpobj.GetPixel(j, i));

                    if (tmpValue > grayGate)
                        tmpValue = 255;
                    else
                        tmpValue = 0;

                    bmpobj.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue));
                }
            }
        }
        /// <summary>
        /// 去图形边框
        /// </summary>
        /// <param name="borderWidth"></param>
        public void ClearPicBorder(int borderWidth)
        {
            for (int i = 0; i < bmpobj.Height; i++)
            {
                for (int j = 0; j < bmpobj.Width; j++)
                {
                    if (i < borderWidth || j < borderWidth || j > bmpobj.Width - 1 - borderWidth || i > bmpobj.Height - 1 - borderWidth)
                        bmpobj.SetPixel(j, i, Color.FromArgb(255, 255, 255));
                }
            }
        }
        /// <summary>
        /// 根据灰度值分割
        /// </summary>
        public Bitmap[] TrimPicByGray(int numCount, int graygate, int miniTrimGate, int minCharWidth, int maxCharWidth)
        {
            //找到垂直投影

            List<int> horizontalgrays = GetHorizontalGrays(graygate);



            //找到最大的n个极点，作为分析点

            List<BitPoint> poslist = new List<BitPoint>();

            //for (int i = 0; i < numCount; i++)
            //{
            //    int grayindex = GetMaxGrayIndex(horizontalgrays);

            //    //在这个index的max区间内找到灰度最大的区间

            //    int startx = (grayindex - maxCharWidth) < 0 ?
            //        0 : (grayindex - maxCharWidth);

            //    int endx = (grayindex + maxCharWidth) > (horizontalgrays.Count - 1) ?
            //        (horizontalgrays.Count - 1) : (grayindex + maxCharWidth);


            //    //如果在startx 右 max/2 的区间出现分界点，则调整

            //    bool needadjusted = false;

            //    for (int j = startx; j < startx + maxCharWidth / 2; j++)
            //    {
            //        if (horizontalgrays[j] <= miniTrimGate)
            //        {
            //            startx = j;

            //            needadjusted = true;
            //        }
            //        else if (needadjusted)
            //        {
            //            break;
            //        }
            //    }

            //    //如果在endx左 max/2 的区间内出现 分界点，则需要调整

            //    needadjusted = false;

            //    for (int j = endx; j > endx - maxCharWidth / 2; j--)
            //    {
            //        if (horizontalgrays[j] <= miniTrimGate)
            //        {
            //            endx = j;

            //            needadjusted = true;
            //        }
            //        else if (needadjusted)
            //        {
            //            break;
            //        }
            //    }

            //    BitPoint point = new BitPoint(startx, endx);

            //    int maxsumgrayvalues = 0;

            //    while (startx + maxCharWidth < endx)
            //    {
            //        int currentsumgrayvalues = GetSumGrayValues(horizontalgrays,
            //            startx,
            //            (startx + maxCharWidth > endx) ? endx : (startx + maxCharWidth));

            //        if (currentsumgrayvalues > maxsumgrayvalues)
            //        {
            //            point.X = startx;

            //            point.Y = (startx + maxCharWidth > endx) ? endx : (startx + maxCharWidth);
            //        }

            //        startx++;
            //    }

            //    poslist.Add(point);

            //    //删除区间内的灰度

            //    for (int j = point.X; j < point.Y; j++)
            //    {
            //        horizontalgrays[j] = 0;
            //    }
            //}


            BitPoint currentPoint = null;

            for (int x = 0; x < horizontalgrays.Count; x++)
            {
                int grayvalue = horizontalgrays[x];

                if (grayvalue > miniTrimGate)
                {
                    if (currentPoint == null)
                    {
                        currentPoint = new BitPoint(x, x);

                        x += minCharWidth;
                    }
                    else
                    {
                        currentPoint.Y = x;
                    }

                    continue;
                }

                if (grayvalue <= miniTrimGate && currentPoint != null)
                {
                    poslist.Add(new BitPoint(currentPoint.X, x));

                    currentPoint = null;

                    continue;
                }
            }

            poslist.Sort();

            Bitmap[] PicArray = new Bitmap[numCount];

            Rectangle cloneRect;

            for (int i = 0; i < (poslist.Count > numCount ? numCount : poslist.Count); i++)      //找有效区
            {
                BitPoint pos = poslist[i];

                cloneRect = new Rectangle(pos.X, 0, pos.Y - pos.X, bmpobj.Height);

                PicArray[i] = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);//复制小块图
            }

            return PicArray;
        }
        /// <summary>
        /// 得到有效图形,图形由外面传入
        /// </summary>
        /// <param name="dgGrayValue">灰度背景分界值</param>
        /// <param name="CharsCount">有效字符数</param>
        /// <returns></returns>
        public Bitmap GetPicValidByValue(Bitmap singlepic, int dgGrayValue)
        {
            int posx1 = singlepic.Width; int posy1 = singlepic.Height;
            int posx2 = 0; int posy2 = 0;
            for (int i = 0; i < singlepic.Height; i++)      //找有效区
            {
                for (int j = 0; j < singlepic.Width; j++)
                {
                    int pixelValue = singlepic.GetPixel(j, i).R;
                    if (pixelValue < dgGrayValue)     //根据灰度值
                    {
                        if (posx1 > j) posx1 = j;
                        if (posy1 > i) posy1 = i;

                        if (posx2 < j) posx2 = j;
                        if (posy2 < i) posy2 = i;
                    };
                };
            };
            //复制新图
            Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1);
            return singlepic.Clone(cloneRect, singlepic.PixelFormat);
        }
        /// <summary>
        /// 对比图，取最大值
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <returns></returns>
        public int Compare(Bitmap org, Bitmap teacher)
        {
            Bitmap template = new Bitmap(org.Width > teacher.Width ? org.Width : teacher.Width,
                org.Height > teacher.Height ? org.Height : teacher.Height);

            Graphics g = Graphics.FromImage(template);

            g.DrawImage(org, (template.Width - org.Width) / 2, (template.Height - org.Height) / 2);

            //对比

            int horizontal = 0;

            int vertical = 0;

            int maxGray = int.MinValue;

            while (horizontal <= (template.Width - teacher.Width) &&
                vertical <= (template.Height - teacher.Height))
            {
                Rectangle cloneRect;

                cloneRect = new Rectangle(horizontal, vertical, teacher.Width, teacher.Height);

                Bitmap smalltemplate = template.Clone(cloneRect, template.PixelFormat);//复制小块图

                int currentgray = GetCompareResult(smalltemplate, teacher);

                if (currentgray > maxGray)
                    maxGray = currentgray;

                horizontal++;

                if (horizontal > (template.Width - org.Width))
                {
                    horizontal = 0;

                    vertical++;
                }
            }

            return maxGray;
        }

        /// <summary>
        /// 对比图片
        /// </summary>
        /// <param name="mapA"></param>
        /// <param name="mapB"></param>
        /// <returns></returns>
        private int GetCompareResult(Bitmap mapA, Bitmap mapB)
        {
            int totalvalue = 0;

            for (int i = 0; i < mapA.Width; i++)
            {
                for (int j = 0; j < mapA.Height; j++)
                {
                    int pixelValueA = mapA.GetPixel(i, j).R > 128 ? 0 : 1;

                    int pixelValueB = mapB.GetPixel(i, j).R > 128 ? 0 : 1;

                    if (pixelValueA == pixelValueB)
                    {
                        if (pixelValueA == 1)
                            totalvalue++;
                    }
                    else
                        totalvalue--;
                }
            }

            return totalvalue;

        }
        /// <summary>
        /// 得到有效图形并调整为可平均分割的大小
        /// </summary>
        /// <param name="dgGrayValue">灰度背景分界值</param>
        /// <param name="CharsCount">有效字符数</param>
        /// <returns></returns>
        private void GetPicValidByValue(int dgGrayValue, int CharsCount)
        {
            int posx1 = bmpobj.Width; int posy1 = bmpobj.Height;
            int posx2 = 0; int posy2 = 0;
            for (int i = 0; i < bmpobj.Height; i++)      //找有效区
            {
                for (int j = 0; j < bmpobj.Width; j++)
                {
                    int pixelValue = bmpobj.GetPixel(j, i).R;
                    if (pixelValue < dgGrayValue)     //根据灰度值
                    {
                        if (posx1 > j) posx1 = j;
                        if (posy1 > i) posy1 = i;

                        if (posx2 < j) posx2 = j;
                        if (posy2 < i) posy2 = i;
                    };
                };
            };
            // 确保能整除
            int Span = CharsCount - (posx2 - posx1 + 1) % CharsCount;   //可整除的差额数
            if (Span < CharsCount)
            {
                int leftSpan = Span / 2;    //分配到左边的空列 ，如span为单数,则右边比左边大1
                if (posx1 > leftSpan)
                    posx1 = posx1 - leftSpan;
                if (posx2 + Span - leftSpan < bmpobj.Width)
                    posx2 = posx2 + Span - leftSpan;
            }
            //复制新图
            Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1);
            bmpobj = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);
        }
        /// <summary>
        /// 得到有效图形,图形为类变量
        /// </summary>
        /// <param name="dgGrayValue">灰度背景分界值</param>
        /// <param name="CharsCount">有效字符数</param>
        /// <returns></returns>
        private void GetPicValidByValue(int dgGrayValue)
        {
            int posx1 = bmpobj.Width; int posy1 = bmpobj.Height;
            int posx2 = 0; int posy2 = 0;
            for (int i = 0; i < bmpobj.Height; i++)      //找有效区
            {
                for (int j = 0; j < bmpobj.Width; j++)
                {
                    int pixelValue = bmpobj.GetPixel(j, i).R;
                    if (pixelValue < dgGrayValue)     //根据灰度值
                    {
                        if (posx1 > j) posx1 = j;
                        if (posy1 > i) posy1 = i;

                        if (posx2 < j) posx2 = j;
                        if (posy2 < i) posy2 = i;
                    };
                };
            };
            //复制新图
            Rectangle cloneRect = new Rectangle(posx1, posy1, posx2 - posx1 + 1, posy2 - posy1 + 1);
            bmpobj = bmpobj.Clone(cloneRect, bmpobj.PixelFormat);
        }
        /// <summary>
        /// 返回灰度图片的点阵描述字串，1表示灰点，0表示背景
        /// </summary>
        /// <param name="singlepic">灰度图</param>
        /// <param name="dgGrayValue">背前景灰色界限</param>
        /// <returns></returns>
        private string GetSingleBmpCode(Bitmap singlepic, int dgGrayValue)
        {
            Color piexl;
            string code = "";
            for (int posy = 0; posy < singlepic.Height; posy++)
                for (int posx = 0; posx < singlepic.Width; posx++)
                {
                    piexl = singlepic.GetPixel(posx, posy);
                    if (piexl.R < dgGrayValue)    // Color.Black )
                        code = code + "1";
                    else
                        code = code + "0";
                }
            return code;
        }


        /// <summary>
        /// 根据RGB，计算灰度值
        /// </summary>
        /// <param name="posClr">Color值</param>
        /// <returns>灰度值，整型</returns>
        private int GetGrayNumColor(System.Drawing.Color posClr)
        {
            return (posClr.R * 19595 + posClr.G * 38469 + posClr.B * 7472) >> 16;
        }
        /// <summary>
        /// 取得水平灰度累计图
        /// </summary>
        /// <returns></returns>
        private List<int> GetHorizontalGrays(int graygate)
        {
            //255,255,255 = white
            //0,0,0 = black

            List<int> list = new List<int>();

            if (bmpobj == null)
                return list;

            for (int j = 0; j < bmpobj.Width; j++)
            {
                int pixelValue = 0;

                for (int i = 0; i < bmpobj.Height; i++)
                {
                    if (graygate > bmpobj.GetPixel(j, i).R)
                        pixelValue += 1;
                }

                list.Add(pixelValue);
            }

            return list;
        }
        /// <summary>
        /// 取得垂直灰度累计图
        /// </summary>
        /// <returns></returns>
        private List<int> GetVerticalGrays(int graygate)
        {
            //255,255,255 = white
            //0,0,0 = black

            List<int> list = new List<int>();

            if (bmpobj == null)
                return list;

            for (int i = 0; i < bmpobj.Height; i++)
            {
                int pixelValue = 0;

                for (int j = 0; j < bmpobj.Width; j++)
                {
                    if (graygate > bmpobj.GetPixel(j, i).R)
                        pixelValue += 1;
                }

                list.Add(pixelValue);
            }

            return list;
        }
        /// <summary>
        /// 取得极致点
        /// </summary>
        /// <returns></returns>
        private int GetMaxGrayIndex(List<int> list)
        {
            int index = 0;
            int maxvalue = 0;

            for (int i = 0; i < list.Count; i++)
            {
                int grayvalue = list[i];

                if (grayvalue > maxvalue)
                {
                    index = i;

                    maxvalue = grayvalue;
                }
            }

            return index;
        }
        /// <summary>
        /// 取得区间内的灰度积累
        /// </summary>
        /// <param name="list"></param>
        /// <param name="startx"></param>
        /// <param name="endx"></param>
        /// <returns></returns>
        private int GetSumGrayValues(List<int> list, int startx, int endx)
        {
            int values = 0;

            for (int i = startx; i < endx; i++)
            {
                if (i > list.Count - 1)
                    return values;

                int currentvalue = list[i];

                values += list[i];
            }

            return values;
        }



        /// <summary>
        /// 图像位置
        /// </summary>
        private class BitPoint : IComparable<BitPoint>
        {
            int x;
            int y;
            public BitPoint(int x, int y)
            {
                this.x = x;
                this.y = y;
            }
            public int X
            {
                get { return x; }
                set { x = value; }
            }
            public int Y
            {
                get { return y; }
                set { y = value; }
            }
            public int Gap
            {
                get
                {
                    return Y - X;
                }
            }

            #region IComparable<BitPoint> 成员

            public int CompareTo(BitPoint other)
            {
                if (other.Gap > this.Gap)
                    return 1;
                else if (other.Gap < this.Gap)
                    return -1;

                return 0;
            }

            #endregion
        }


        private void test()
        {
            string orgpath = @"E:\玩转上海交大\00程序设计学习\_DAY25\20090812开心网图片识别\training\";


            string path = orgpath + "teacher_num.bmp";

            UnCodebase code = new UnCodebase((Bitmap)Image.FromFile(path));

            code.SecondGrayByPixels(160);

            //code.ClearPicBorder(1);

            //code.bmpobj.Save(@"E:\玩转上海交大\00程序设计学习\_DAY25\20090812开心网图片识别\result\img_" + tt + "_all.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);

            Bitmap[] imgs = code.TrimPicByGray(10, 160, 2, 9, 20);

            List<Bitmap> imglist = new List<Bitmap>();

            foreach (Bitmap img in imgs)
            {
                imglist.Add(code.GetPicValidByValue(img, 10));
            }

            //List<string> charlist = new List<string>();

            int counter = 0;

            foreach (Bitmap img in imglist)
            {
                counter++;

                img.Save(orgpath + "char_num" + counter + ".bmp",
                    System.Drawing.Imaging.ImageFormat.Bmp);
            }



        }
    }
}
